package com.net.xpay.common.service.impl;

import com.net.xpay.common.domain.DailyTaskRecord;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.domain.partner.Partner;
import com.net.xpay.common.domain.partner.PartnerCombinationSettleRecord;
import com.net.xpay.common.enums.partner.PartnerCombinationSettleRecordType;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.core.manager.PayTransBatchManager;
import com.net.xpay.core.manager.safePay.SafePayBatchManager;
import com.net.xpay.core.model.UserPayTransStatCommonModel;
import com.net.xpay.core.model.UserSafePayTransStatCommonModel;
import com.net.xpay.core.model.UserSafePayTransStatModel;
import com.net.xpay.core.model.UserTransStatModel;
import com.net.xpay.core.utils.BeanCopierUtil;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.MoneyUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.common.manager.partner.PartnerCombinationSettleRecordManager;
import com.net.xpay.common.manager.partner.PartnerManager;
import com.net.xpay.common.service.PartnerCombinationSettleService;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class PartnerCombinationSettleServiceImpl implements PartnerCombinationSettleService  {
    @Autowired
    private PartnerManager partnerManager;

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private SafePayBatchManager safePayBatchManager;

    @Autowired
    private PayTransBatchManager payTransBatchManager;


    @Autowired
    private PartnerCombinationSettleRecordManager partnerCombinationSettleRecordManager;

    @Override
    public void statPartnerCombinationSettleRecord(LocalDate day, DailyTaskRecord record) {
        //拉出所有合伙人
        List<Partner> partners = partnerManager.listAll();
        record.setTotalCount((long) partners.size());
        log.info("statPartnerCombinationSettleRecord partnerIds={}", StreamUtil.map(partners, Partner::getId));
        if (CollectionUtils.isEmpty(partners)) {
            return;
        }

        //遍历合伙人一个个的生成统计记录 注意保证幂等性统计过的就不要再统计了
        for (Partner partner : partners) {
            try {
                doStatPartnerCombinationSettleRecord(partner, day);
            } catch (Exception e) {
                log.error("statPartnerCombinationSettleRecord error|partnerId={}", partner.getId(), e);
                record.setFailedCount(record.getFailedCount() + 1L);
                continue;
            }

            record.setSuccessCount(record.getSuccessCount() + 1L);
        }
    }

    private void doStatPartnerCombinationSettleRecord(Partner partner, LocalDate day) {
        //注册时间在统计时间之后的不统计
        if (partner.getRegisterTime().toLocalDate().isAfter(day)) {
            return;
        }
        //查询合伙人下的所有用户
        List<User> users = userManager.listByPartnerId(partner.getId());
        if (CollectionUtils.isEmpty(users)) {
            log.warn("doStatPartnerCombinationSettleRecord There are no users at this time");
            return;
        }
        for (User user : users) {
            //统计安全发
            doStatPartnerSafePaySettleRecord(user, day);
            //统计批量有密
            doStatPartnerPayTransSettleRecord(user, day);
        }

    }

    //统计安全发
    private void doStatPartnerSafePaySettleRecord(User user, LocalDate day) {
        PartnerCombinationSettleRecord record = new PartnerCombinationSettleRecord();
        // 通过userID获取到userShard
        UserShard userShard = userShardManager.getById(user.getId());
        try {
            // 先去判断该用户当天转账金额记录是否存在
            record.setDay(day);
            record.setYear(day.getYear());
            record.setMonth(day.getMonthValue());
            record.setUserId(user.getId());
            record.setPartnerId(user.getPartnerId());
            record.setType(PartnerCombinationSettleRecordType.SAFE_PAY);
            record.setSettled(false);
            record.setServiceRatio(user.getServiceRatio());
            record.setBankServiceRatio(user.getBankServiceRatio());
            record.setCommissionMode(user.getCommissionMode());
            record.setBenefitRatio(user.getBenefitRatio());
            record.setCostServiceRatio(user.getCostServiceRatio());
            record.setBankCostServiceRatio(user.getBankCostServiceRatio());
            boolean exitRecord = hasStatPartnerCombinationSettleRecord(user.getId(), day, PartnerCombinationSettleRecordType.SAFE_PAY);
            if (exitRecord) {
                log.warn("doStatPartnerSafePaySettleRecord the record of userId={}|day={} is already exist", user.getId(), day);
                return;
            }
            // 切库处理
            ShardUtil.setShardContext(userShard.getShardId());
            // 获取当天的起始时间和终止时间 终止时间保留在23:59:59.999999999
            LocalDateTime minEndTime = LocalDateUtil.getDayStart(day);
            LocalDateTime maxEndTime = LocalDateUtil.getDayEnd(day);
            UserSafePayTransStatModel recordModel = safePayBatchManager.countAmountAndTimesOfSuccess(user.getId(), minEndTime, maxEndTime);

            record.setFinalServiceAmount(MoneyUtil.convertCentToBigDecimal(recordModel.getFinalServicePrice(), 2));
            record.setPartnerSettleAmount(MoneyUtil.convertCentToBigDecimal(recordModel.getTotalPartnerBenefit(), 2));
            record.setTotalTransAmount(new BigDecimal(recordModel.getTotalTransAmount()));
            record.setTotalCount(recordModel.getTotalCount());
            record.setSuccessAmount(new BigDecimal(recordModel.getSuccessAmount()));
            record.setSuccessCount(recordModel.getSuccessCount());
            record.setFailedAmount(new BigDecimal(recordModel.getFailedAmount()));
            record.setFailCount(recordModel.getFailCount());

            UserSafePayTransStatCommonModel userSafePayTransStatCommonBankModel = safePayBatchManager.countAmountAndTimesOfSuccessBank(user.getId(), minEndTime, maxEndTime);
            UserSafePayTransStatCommonModel userSafePayTransStatCommonAlipayModel = safePayBatchManager.countAmountAndTimesOfSuccessAlipay(user.getId(), minEndTime, maxEndTime);
            //不免费的统计
            UserSafePayTransStatCommonModel userSafePayTransStatCommonNotFreeBankModel = safePayBatchManager.countAmountAndTimesOfSuccessNotFreeBank(user.getId(), minEndTime, maxEndTime);
            UserSafePayTransStatCommonModel userSafePayTransStatCommonNotFreeAlipayModel = safePayBatchManager.countAmountAndTimesOfSuccessNotFreeAlipay(user.getId(), minEndTime, maxEndTime);

            //到卡
            record.setSuccessBankAmount(new BigDecimal(userSafePayTransStatCommonBankModel.getSuccessAmount()));
            record.setSuccessBankCount(userSafePayTransStatCommonBankModel.getSuccessCount());
            //到支付宝
            record.setSuccessAlipayAmount(new BigDecimal(userSafePayTransStatCommonAlipayModel.getSuccessAmount()));
            record.setSuccessAlipayCount(userSafePayTransStatCommonAlipayModel.getSuccessCount());
            //不免费到卡
            record.setNotFreeSuccessBankAmount(new BigDecimal(userSafePayTransStatCommonNotFreeBankModel.getSuccessAmount()));
            record.setNotFreeSuccessBankCount(userSafePayTransStatCommonNotFreeBankModel.getSuccessCount());
            //不免费到支付宝
            record.setNotFreeSuccessAlipayAmount(new BigDecimal(userSafePayTransStatCommonNotFreeAlipayModel.getSuccessAmount()));
            record.setNotFreeSuccessAlipayCount(userSafePayTransStatCommonNotFreeAlipayModel.getSuccessCount());
            //不免费的总金额 / 笔数
            record.setNotFreeSuccessAmount(new BigDecimal(new BigDecimal(userSafePayTransStatCommonNotFreeBankModel.getSuccessAmount()).add(new BigDecimal(userSafePayTransStatCommonNotFreeAlipayModel.getSuccessAmount())).toString()));
            record.setNotFreeSuccessCount(userSafePayTransStatCommonNotFreeBankModel.getSuccessCount() + userSafePayTransStatCommonNotFreeAlipayModel.getSuccessCount());

            // 数据入库
            if (user.getFatherPartnerId() == null) {
                partnerCombinationSettleRecordManager.save(record);
            } else {
                //同时保存 当前合伙人收益和上级合伙人收益
                PartnerCombinationSettleRecord fatherRecord = new PartnerCombinationSettleRecord();
                BeanCopierUtil.copy(record, fatherRecord);
                fatherRecord.setPartnerId(user.getFatherPartnerId());
                fatherRecord.setTwoLevelPartnerId(user.getPartnerId());
                fatherRecord.setTwoLevelBenefitRatio(user.getFatherBenefitRatio());
                fatherRecord.setTwoLevelCommissionMode(user.getFatherCommissionMode());
                fatherRecord.setTwoLevelServiceRatio(user.getFatherServiceRatio());
                fatherRecord.setTwoLevelBankServiceRatio(user.getFatherBankServiceRatio());
                fatherRecord.setPartnerSettleAmount(MoneyUtil.convertCentToBigDecimal(recordModel.getTotalFatherPartnerBenefit(), 2));
                partnerCombinationSettleRecordManager.bothSave(record, fatherRecord);
            }


        } finally {
            ShardUtil.cleanShardContext();
        }
    }

    private void doStatPartnerPayTransSettleRecord(User user, LocalDate day) {
        PartnerCombinationSettleRecord record = new PartnerCombinationSettleRecord();
        // 通过userID获取到userShard
        UserShard userShard = userShardManager.getById(user.getId());
        try {
            // 先去判断该用户当天转账金额记录是否存在
            record.setDay(day);
            record.setYear(day.getYear());
            record.setMonth(day.getMonthValue());
            record.setUserId(user.getId());
            record.setPartnerId(user.getPartnerId());
            record.setType(PartnerCombinationSettleRecordType.BATCH_PSW);
            record.setSettled(false);
            record.setServiceRatio(user.getServiceRatio());
            record.setBankServiceRatio(user.getBankServiceRatio());
            record.setCommissionMode(user.getCommissionMode());
            record.setBenefitRatio(user.getBenefitRatio());
            record.setCostServiceRatio(user.getCostServiceRatio());
            record.setBankCostServiceRatio(user.getBankCostServiceRatio());
            boolean exitRecord = hasStatPartnerCombinationSettleRecord(user.getId(), day, PartnerCombinationSettleRecordType.BATCH_PSW);
            if (exitRecord) {
                log.warn("doStatPartnerPayTransSettleRecord the record of userId={}|day={} is already exist", user.getId(), day);
                return;
            }
            // 切库处理
            ShardUtil.setShardContext(userShard.getShardId());
            // 获取当天的起始时间和终止时间 终止时间保留在23:59:59.999999999
            LocalDateTime minEndTime = LocalDateUtil.getDayStart(day);
            LocalDateTime maxEndTime = LocalDateUtil.getDayEnd(day);
            UserTransStatModel recordModel = payTransBatchManager.countAmountAndTimesOfSuccess(user.getId(), minEndTime, maxEndTime);
            record.setFinalServiceAmount(MoneyUtil.convertCentToBigDecimal(recordModel.getServicePrice() - recordModel.getRefund(), 2));
            record.setPartnerSettleAmount(MoneyUtil.convertCentToBigDecimal(recordModel.getTotalPartnerBenefit(), 2));
            record.setTotalTransAmount(new BigDecimal(recordModel.getTotalTransAmount()));
            record.setTotalCount(recordModel.getTotalCount());
            record.setSuccessAmount(new BigDecimal(recordModel.getSuccessAmount()));
            record.setSuccessCount(recordModel.getSuccessCount());
            record.setFailedAmount(new BigDecimal(recordModel.getFailedAmount()));
            record.setFailCount(recordModel.getFailCount());
            //到卡
            record.setSuccessBankAmount(new BigDecimal("0.00"));//批量有密目前没有到卡的
            record.setSuccessBankCount(0L);
            //到支付宝
            record.setSuccessAlipayAmount(new BigDecimal(recordModel.getSuccessAmount()));
            record.setSuccessAlipayCount(recordModel.getSuccessCount());

            //计费的批次数据
            UserPayTransStatCommonModel statCommonModel = payTransBatchManager.countNoFreeAmountAndTimesOfSuccess(user.getId(), minEndTime, maxEndTime);

            //不免费到卡
            record.setNotFreeSuccessBankAmount(new BigDecimal("0.00"));
            record.setNotFreeSuccessBankCount(0L);
            //不免费到支付宝
            record.setNotFreeSuccessAlipayAmount(new BigDecimal(statCommonModel.getSuccessAmount()));
            record.setNotFreeSuccessAlipayCount(statCommonModel.getSuccessCount());
            //不免费的总金额 / 笔数
            record.setNotFreeSuccessAmount(record.getNotFreeSuccessAlipayAmount().add(record.getNotFreeSuccessBankAmount()));
            record.setNotFreeSuccessCount(record.getNotFreeSuccessAlipayCount() + record.getNotFreeSuccessBankCount());

            // 数据入库
            if (user.getFatherPartnerId() == null) {
                partnerCombinationSettleRecordManager.save(record);
            } else {
                //同时保存 当前合伙人收益和上级合伙人收益
                PartnerCombinationSettleRecord fatherRecord = new PartnerCombinationSettleRecord();
                BeanCopierUtil.copy(record, fatherRecord);
                fatherRecord.setPartnerId(user.getFatherPartnerId());
                fatherRecord.setTwoLevelPartnerId(user.getPartnerId());
                fatherRecord.setTwoLevelBenefitRatio(user.getFatherBenefitRatio());
                fatherRecord.setTwoLevelCommissionMode(user.getFatherCommissionMode());
                fatherRecord.setTwoLevelServiceRatio(user.getFatherServiceRatio());
                fatherRecord.setTwoLevelBankServiceRatio(user.getFatherBankServiceRatio());
                fatherRecord.setPartnerSettleAmount(MoneyUtil.convertCentToBigDecimal(recordModel.getTotalFatherPartnerBenefit(), 2));
                partnerCombinationSettleRecordManager.bothSave(record, fatherRecord);
            }
        } finally {
            ShardUtil.cleanShardContext();
        }
    }


    private boolean hasStatPartnerCombinationSettleRecord(Long userId, LocalDate day, PartnerCombinationSettleRecordType type) {
        // 尝试通过时间加id获取数据
        PartnerCombinationSettleRecord selectedRecord = partnerCombinationSettleRecordManager.findByDayAndUserId(userId, day, type);
        // 若果查到了数据，表示不需要在插入记录了
        return selectedRecord != null;
    }

}
